import type { StyleTagOptions } from '../index'
import { logger } from '../../../types/constants'
import { SYMBOLS } from '../../../types/interfaces'
import { FrameworkType } from '../../utils/base/environment'
import { ToolKit } from '../../utils/toolkit'
import { StyleBaseInjector } from '../base'

/**
 * 跨框架 CSS 注入配置接口
 */
export interface CrossFrameworkInjectionConfig {
  /** 需要适配的框架列表 */
  frameworks: FrameworkType[]
  /** 是否启用深度选择器 */
  enableDeepSelectors: boolean
  /** 样式优先级提升策略 */
  priorityBoost: 'auto' | 'important' | 'specificity'
  /** 重试注入次数 */
  retryAttempts: number
  /** 框架检测超时时间(ms) */
  detectionTimeout: number
  /** 是否启用 Shadow DOM 支持 */
  enableShadowDOM: boolean
  /** 是否启用 MutationObserver 监听 */
  enableLifecycleReinjection: boolean
  /** 样式隔离级别 */
  isolationLevel: 'none' | 'scoped' | 'shadow'
}

/**
 * 跨框架 CSS 注入器
 */
export class CrossFrameworkInjector extends StyleBaseInjector {
  readonly name: string = 'CrossFrameworkInjector'
  private readonly config: CrossFrameworkInjectionConfig = {
    frameworks: [FrameworkType.React, FrameworkType.Vue, FrameworkType.Angular],
    enableDeepSelectors: true,
    priorityBoost: 'auto',
    retryAttempts: 3,
    detectionTimeout: 5000,
    enableShadowDOM: true,
    enableLifecycleReinjection: true,
    isolationLevel: 'scoped',
  }

  readonly styleTags: Map<string, HTMLStyleElement[]> = new Map()
  private readonly frameworkStyles: Map<string, Map<string, HTMLStyleElement>> = new Map()
  private readonly mutationObservers: Map<string, MutationObserver> = new Map()
  private frameworkDetectionPromise: Promise<FrameworkType[]> | null = null

  constructor(config?: CrossFrameworkInjectionConfig) {
    super()
    this.config = { ...this.config, ...config }
    // this.initializeFrameworkDetection()
  }

  destroy(): void {
    this.styleTags.forEach(styles => styles.forEach(style => style.remove()))
    this.styleTags.clear()
    this.frameworkStyles.clear()

    // 清理 MutationObserver
    this.mutationObservers.forEach(observer => observer.disconnect())
    this.mutationObservers.clear()
  }

  /**
   * 初始化框架检测
   */
  initializeFrameworkDetection(): void {
    if (this.config.frameworks.length === 0) {
      logger.debug(`[${this.name}] 未配置框架列表，跳过检测`)
      return
    }

    this.frameworkDetectionPromise = new Promise((resolve) => {
      setTimeout(() => {
        const detectedFrameworks = this.detectEnabledFrameworks()

        if (detectedFrameworks.length === 0) {
          logger.hint(`[${this.name}] ${SYMBOLS.UI.SPY} 未检测到任何启用的框架`)
        }
        else {
          logger.important(`[${this.name}] ${SYMBOLS.UI.SPY} 检测到框架: ${detectedFrameworks.join(', ')}`)
        }
        resolve(detectedFrameworks)
      }, this.config.detectionTimeout)
    })
  }

  /**
   * 检测启用的框架
   */
  private detectEnabledFrameworks(): FrameworkType[] {
    const allFrameworks = ToolKit.environment.detectFramework()
    return allFrameworks.filter(framework =>
      this.config.frameworks.includes(framework as any),
    )
  }

  createStyleTag(
    id: string,
    content: string,
    options?: StyleTagOptions,
  ): HTMLStyleElement | null {
    const {
      onlyCreate = false,
      allowEmpty = false,
    } = options || {}

    if (!this.checkContentValidity(id, content, onlyCreate, allowEmpty))
      return null

    const style = document.createElement('style')
    style.id = this.generateStyleId(id)
    style.setAttribute('data-scope', 'cross-framework')
    style.setAttribute('data-framework', 'global')

    // 应用样式隔离配置
    this.applyIsolationLevel(style)

    if (onlyCreate) {
      logger.debug(`[${this.name}] ${SYMBOLS.UI.BOOKMARK} 创建跨框架空样式标签: id='${id}'`)
      this.trackStyle(id, style)
      return style
    }

    const processedContent = this.processFrameworkStyle(content)
    style.textContent = this.processStyleContent(processedContent)
    this.injectStyle(style, options)

    return style
  }

  removeStyleTag(id: string): boolean {
    const styles = this.styleTags.get(id)

    if (!styles || styles.length === 0) {
      logger.warn(`[${this.name}] 样式标签不存在: id='${id}'`)
      return false
    }

    styles.forEach(style => style.remove())
    this.styleTags.delete(id)

    // 清理框架特定样式
    this.frameworkStyles.forEach(frameworkMap => frameworkMap.delete(id))

    // 清理 MutationObserver
    const observer = this.mutationObservers.get(id)
    if (observer) {
      observer.disconnect()
      this.mutationObservers.delete(id)
    }

    logger.success(`[${this.name}] ${SYMBOLS.UI.BOOKMARK} 样式标签已移除: id='${id}'`)
    return true
  }

  injectStyle(style: HTMLStyleElement, options: StyleTagOptions = {}): boolean {
    const { override = true, retryCount = 0 } = options
    const id = style.id.replace('cross-', '')

    try {
      // 等待框架检测完成
      this.ensureFrameworkDetection().then(() => {
        // 多层级注入策略
        this.injectToGlobalDocument(style, override)

        if (this.config.enableShadowDOM)
          this.injectToFrameworkRoots(style, id, override)

        if (this.config.enableLifecycleReinjection) {
          this.setupLifecycleReinjection(style, id)
        }

        this.trackStyle(id, style)
        ToolKit.ui.style.markBaiduSearchElement(style)
        logger.success(`[${this.name}] ${SYMBOLS.UI.BOOKMARK} 跨框架样式注入完成: id='${id}'`)
      })

      return true
    }
    catch (error) {
      logger.error(`[${this.name}] 跨框架样式注入失败: id='${id}'`, error)

      // 重试逻辑
      if (retryCount < this.config.retryAttempts) {
        logger.warn(`[${this.name}] 重试注入 (${retryCount + 1}/${this.config.retryAttempts}): id='${id}'`)
        setTimeout(() => {
          this.injectStyle(style, { ...options, retryCount: retryCount + 1 })
        }, 100 * 2 ** retryCount) // 指数退避
      }

      return false
    }
  }

  updateStyle(id: string, content: string, _options: StyleTagOptions = {}): boolean {
    const styles = this.styleTags.get(id)

    if (!styles) {
      logger.warn(`[${this.name}] 跨框架样式不存在: id='${id}'`)
      return false
    }

    const processedContent = this.processFrameworkStyle(content)
    const finalContent = this.processStyleContent(processedContent)
    styles.forEach((style) => {
      style.textContent = finalContent
    })

    logger.success(`[${this.name}] ${SYMBOLS.UI.BOOKMARK} 跨框架样式更新成功: id='${id}'`)
    return true
  }

  /**
   * 确保框架检测完成
   */
  private async ensureFrameworkDetection(): Promise<void> {
    if (this.frameworkDetectionPromise) {
      await this.frameworkDetectionPromise
    }
  }

  getStyleTag(id: string): HTMLStyleElement[] | null {
    const styleId = this.generateStyleId(id)
    return this.styleTags.get(styleId) || null
  }

  generateStyleId(id: string): string {
    return `cross-${id}`
  }

  /**
   * 应用样式隔离级别
   */
  private applyIsolationLevel(style: HTMLElement): void {
    switch (this.config.isolationLevel) {
      case 'scoped':
        style.setAttribute('scoped', '')
        break
      case 'shadow':
        style.setAttribute('data-shadow-isolation', 'true')
        break
      case 'none':
      default:
        // 无额外隔离
        break
    }
  }

  /**
   * 注入到全局文档头
   */
  private injectToGlobalDocument(style: HTMLStyleElement, override: boolean): void {
    const existingStyle = document.getElementById(style.id) as HTMLStyleElement | null

    if (existingStyle) {
      if (!override)
        return
      existingStyle.remove()
    }

    document.head.appendChild(style)
  }

  /**
   * 注入到框架根元素
   */
  private injectToFrameworkRoots(style: HTMLStyleElement, id: string, override: boolean): void {
    const frameworks = ToolKit.environment.detectFramework()

    frameworks.forEach((framework) => {
      const rootElement = this.findFrameworkRoot(framework)
      if (rootElement?.shadowRoot) {
        const frameworkStyle = style.cloneNode(true) as HTMLStyleElement
        frameworkStyle.id = `${style.id}-${framework}`

        this.injectToShadowRoot(frameworkStyle, rootElement.shadowRoot, override)
        this.trackFrameworkStyle(id, framework, frameworkStyle)
      }
    })
  }

  /**
   * 注入到 Shadow DOM 根元素
   */
  private injectToShadowRoot(style: HTMLStyleElement, shadowRoot: ShadowRoot, override: boolean): void {
    const existingStyle = shadowRoot.getElementById(style.id)
    if (existingStyle) {
      if (!override)
        return
      existingStyle.remove()
    }
    shadowRoot.appendChild(style)
  }

  /**
   * 设置框架更新后的生命周期重新注入
   */
  private setupLifecycleReinjection(style: HTMLStyleElement, id: string): void {
    if (!this.config.enableLifecycleReinjection)
      return

    const observer = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === 'childList' && !document.contains(style)) {
          // 样式被移除，重新注入
          const newStyle = style.cloneNode(true) as HTMLStyleElement
          document.head.appendChild(newStyle)
          logger.hint(`[${this.name}] ${SYMBOLS.UI.BOOKMARK} 框架更新后重新注入样式: id='${id}'`)
          break
        }
      }
    })

    observer.observe(document.body, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['class', 'id'], // 监控可能影响样式的重要属性变化
    })

    this.mutationObservers.set(id, observer)
  }

  /**
   * 跟踪跨框架样式标签
   */
  private trackStyle(id: string, style: HTMLStyleElement): void {
    if (!this.styleTags.has(id)) {
      this.styleTags.set(id, [])
    }
    this.styleTags.get(id)!.push(style)
  }

  /**
   * 跟踪跨框架样式标签
   */
  private trackFrameworkStyle(id: string, framework: string, style: HTMLStyleElement): void {
    if (!this.frameworkStyles.has(framework)) {
      this.frameworkStyles.set(framework, new Map())
    }
    this.frameworkStyles.get(framework)!.set(id, style)
  }

  /**
   * 查找框架根元素
   */
  private findFrameworkRoot(framework: FrameworkType): Element | null {
    const selectors = {
      [FrameworkType.React]: ['[data-reactroot]', '#root', '#app', '[data-react-app]'],
      [FrameworkType.Vue]: ['[data-v-app]', '[v-app]', '#app', '[vue-app]'],
      [FrameworkType.Angular]: ['[ng-version]', '[ng-app]', '[data-ng-app]'],
      [FrameworkType.Svelte]: ['[data-svelte]', '[svelte-app]'],
      [FrameworkType.Solid]: ['[data-solid]', '[solid-app]'],
    }

    const frameworkSelectors = selectors[framework] || []
    for (const selector of frameworkSelectors) {
      const element = document.querySelector(selector)
      if (element)
        return element
    }

    return null
  }

  /**
   * 处理跨框架样式内容
   */
  private processFrameworkStyle(content: string): string {
    let processedContent = content

    if (this.config.enableDeepSelectors) {
      // Vue 深度选择器
      processedContent = processedContent.replace(/:deep\(([^)]+)\)/g, '$1')
      // Angular 样式穿透
      processedContent = processedContent.replace(/::ng-deep\s+/g, '')
      // Svelte 全局样式
      processedContent = processedContent.replace(/:global\(([^)]+)\)/g, '$1')
    }

    return processedContent
  }

  /**
   * 获取当前注入统计
   */
  getInjectionStats(): {
    totalStyles: number
    frameworkStyles: {
      framework: string
      count: number
    }[]
    activeObservers: number
  } {
    return {
      totalStyles: this.styleTags.size,
      frameworkStyles: Array.from(this.frameworkStyles.entries()).map(([fw, styles]) => ({
        framework: fw,
        count: styles.size,
      })),
      activeObservers: this.mutationObservers.size,
    }
  }
}
